/*********************************************************************************
 *    Copyright:  (C) 2023 LN
 *    All rights reserved.
 *
 *       Filename:  socket_server_epoll.c
 *    Description:  This file 
 *                 
 *      Version:  1.0.0(2023年04月05日)
 *       Author:  Li Haipeng <NULL>
 *    ChangeLog:  1, Release initial version on "2023年04月05日 23时38分38秒"
 *                    
 *
 ********************************************************************************/
#include <stdio.h>
#include <poll.h>
#include <sys/epoll.h>
#include <sys/resource.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <getopt.h>
#include <unistd.h>
#include <pthread.h>
#include <ctype.h>
#include "database.h"
#include "logger.h"
#include "pack_data.h"
#include "socket_client.h"

//#define MAX_EVENTS      512
//#define ARRAY_SIZE(x)   (sizeof(x)/sizeof(x[0]))

static inline void msleep(unsigned long ms);
void set_socket_rlimit(void);

static inline void print_usage(char *progname)
{
    printf("Usage: %s [OPTION]...\n", progname);
    printf(" %s is a socket server progname,which uesd to verify client and echo back string from it\n", progname);
    printf("\nMandatory arguments to long options are mandatory for short options too:\n");
    printf("-b(--daemon):set progname running on background\n");
    printf("-p(--port):socket server port address\n");
    printf("-h(--help):Dispaly this help information.\n");
    printf("\nExample: %s -b -p 8900\n", progname);
    return ;
}


int main(int argc,char **argv)
{
    char                        *progname = NULL;
    char                        *buf_start = NULL;
    char                        *buf_end = NULL;
    fd_set                       rdset;
    int                          connfd = -1;
    int                          listenfd;
    int                          found;
    int                          daemon_run = 0;
    int	                         i;
    int	                         j;
    int	                         x = 1;
    int                          rv = -1;
    int	                         epollfd;
    int	                         events;
    int                          ch;
    int                          on = 1;
    struct epoll_event	         event;
    struct epoll_event           event_array[MAX_EVENTS];
    char                         buf[1024];
    char                         text[1024];
    char                         temp[8];
	socket_t					 sock;
	packet_t					 pack;
    struct option                opts[] = {
                                            {"deamon", no_argument, NULL,'b'},
                                            {"port", no_argument, NULL,'p'},
                                            {"help", no_argument, NULL,'h'},
                                            {NULL,0,NULL,0},
                                          };


	sock.port = 6666;
	memset(sock.host, 0, sizeof(sock.host));
	strcpy(sock.host, "hello");

    while((ch=getopt_long(argc , argv ,"bp:h" , opts , NULL)) != -1)
    {
        switch(ch)
        {
            case 'b':
                daemon_run = 1;
                break;
            case 'p':
                sock.port = atoi(optarg);
                break;
            case 'h':
                print_usage(argv[0]);
                return 0;
        }
    }

    if( !sock.port )
    {
        print_usage(argv[0]);
        return 0;
    }

    if(argc < 1)
    {
        printf("Program usage:%s [ServerIP] [port]\n", argv[0]);
        return -1;
    }

    set_socket_rlimit();

    if((listenfd = socket_server_init(&sock)) < 0)
    {
       	printf("ERROR: %s server listen on port %d failure\n", argv[0], sock.port);
        return -2;
    }
    printf("%s server start to listen on port %d\n", argv[0], sock.port);

    if(daemon_run)
    {
        daemon(0, 0);
    }

    if(( epollfd = epoll_create(MAX_EVENTS)) < 0 )
    {
        printf("epoll_create() failure: %s\n", strerror(errno));
        return -3;	
    }

    event.events = EPOLLIN | EPOLLET;
    event.data.fd = listenfd;

    if( epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &event) < 0)
    {
        printf("epoll add listenfd socket failure: %s\n", strerror(errno));
        return -4;
    }

    if(logger_init(NULL, 0) < 0)
    {
        fprintf(stderr,"initial logger system failure\n");
    }

    for( ; ; )
    {
        events = epoll_wait(epollfd, event_array, MAX_EVENTS, -1);
        if(events < 0)
        {
            log_debug("epoll failure: %s\n", strerror(errno));
            break;
        }

        else if(events == 0)
        {
            log_debug("epoll get timeout\n");
        }
	
        for(i = 0; i < events; i++)
        {
            if( (event_array[i].events & POLLERR) || (event_array[i].events & EPOLLHUP) )
            {
                log_debug("epoll_wait get error on fd[%d]: %s\n", event_array[i].data.fd, strerror(errno));
                epoll_ctl(epollfd, EPOLL_CTL_DEL, event_array[i].data.fd, NULL);
                close(event_array[i].data.fd);
            }
            if(event_array[i].data.fd == listenfd)
            {
                if((connfd = accept(listenfd, (struct sockaddr *)NULL, NULL)) < 0)
                {		
                    log_debug("accept new client failure: %s\n", strerror(errno));
                    continue;
                }

                event.data.fd = connfd;
                event.events = EPOLLIN;

                if(epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &event) < 0)
                {
                    log_debug("epoll add client socket failure: %s\n", strerror(errno));
                    close(event_array[i].data.fd);
                    continue;
                }
		
                log_debug("epoll add new client socket[%d] pk.\n", connfd);
		
            }

            else
            {
				memset(buf, 0, sizeof(buf));
                if((rv = read(event_array[i].data.fd, buf, sizeof(buf))) <= 0)
                {
                    log_debug("socket[%d] read failure or get disconnect.\n", event_array[i].data.fd);
                    close(event_array[i].data.fd);
                    continue;
                }
                else
                {
                    log_debug("socket[%d] read get %d bytes data:%s\n", event_array[i].data.fd, rv, buf);
                    printf("socket[%d] read get %d bytes data:%s\n", event_array[i].data.fd, rv, buf);

					buf_start = buf;
					while(1)
					{
						if(rv > 38)
						{
							buf_end = buf_start + 38;
							memset(text, 0, sizeof(text));
							memcpy(text, buf_start, buf_end - buf_start);
							buf_start = buf_end;
						}
						else
						{
							buf_end = buf_start + 38;
							memset(text, 0, sizeof(text));
							memcpy(text, buf_start, buf_end - buf_start);
						}
						unpack_data(&pack, text, strlen(text));

                    	open_db(&pack);
                    	insert_data(&pack);
						close_db();
						if( !(rv = rv -38) )
						{
							break;
						}
					}
                }
            }	    
        }
    }
CleaUp:
    close(listenfd);
    return 0;
}
